#ifndef __CUDA_BUF_CU__
#define __CUDA_BUF_CU__

/**
 a simple memory buffer management class
 memory only can be requested sequentially
 either GPU or CPU memory can use this class
*/

#include "cuda_header.h"
#include "mian_util.h"

enum MemoryKind {GMEM, CMEM};

struct st_MemoryBuf {
	byte* d_buf;
	uint64 bufSize;		//bytes
	uint64 usedSize;	//bytes
	bool isAllocated;	//whether d_buf is allocated by the class
	MemoryKind memKind;

	/*if the memory is allocated outside*/
	st_MemoryBuf(byte* d_mem, const uint64 in_size, const MemoryKind in_memKind) {
		this->d_buf = d_mem;
		this->bufSize = in_size;
		this->usedSize = 0;
		this->isAllocated = false;
		this->memKind = in_memKind;
	}

	/*allocate the memory by the class*/
	st_MemoryBuf(const uint64 in_size, const MemoryKind in_memKind) {
		this->bufSize = in_size;
		this->usedSize = 0;
		this->isAllocated = true;
		this->memKind = in_memKind;
		
		if(GMEM == memKind) {
			printf("bufSize = %d", bufSize);
			GPUMALLOC((void**)&d_buf, bufSize);
		} else {
			this->d_buf = (byte*)malloc(bufSize);
		}
	}

	void close() {
		if(true == isAllocated && d_buf != NULL) {
			if(GMEM == memKind) {
				GPUFREE(d_buf);
			} else {
				free(d_buf);
			}
		} 

		d_buf = NULL;
		usedSize = 0;
		bufSize = 0;
		isAllocated = false;
	}

	void reset() {
		usedSize = 0;	
	}


	//return a pointer for the non-used memory
	byte* newMem(const uint64 size) {
		if(size + usedSize > bufSize) {
			printf("requesed size:  %lu bytes\n", size);
			printf("available size: %lu bytes\n", bufSize - usedSize);
			ERROR_EXIT("requested memory size is too large");
		}

		byte* d_ptr = d_buf + usedSize;
		usedSize += size;

		return d_ptr;
	}

	//return the available size of the buffer
	uint64 freeSize() {
		assert(bufSize >= usedSize);
		return bufSize - usedSize;
	}

	//release a chunk of memory from the tail of the buffer, this operations may be risky
	void release(const uint64 releaseSize) {
		if(releaseSize > usedSize) {
			ERROR_EXIT("the buffer to release exceeds the size of the buffer");
		}

		usedSize -= releaseSize;
	}
};


#endif /*__CUDA_BUF_CU__*/


